package cqrtplm.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.hustcad.plm.basic.log.LogEventEnum;
import com.hustcad.plm.basic.log.TyplmLogger;
import com.hustcad.plm.basic.util.TyplmLoggerUtil;
import com.hustcad.plm.pdm.basedrule.dto.TyplmBaseRuleBoundedObjDTO;
import com.hustcad.plm.pdm.basedrule.service.TyplmBasedRuleService;
import com.hustcad.plm.pdm.code.model.dto.codemanagement.TyplmSegmentCodeConditionDTO;
import com.hustcad.plm.pdm.code.model.vo.codemanagement.segmentcode.TyplmSegmentCodeRuleVO;
import com.hustcad.plm.pdm.code.service.codemanagement.TyplmSegmentCodeService;
import com.hustcad.plm.pdm.ec.module.dto.AffectedObjectDTO;
import com.hustcad.plm.pdm.ec.module.dto.TyplmChangeIssueDetailDTO;
import com.hustcad.plm.pdm.ec.module.dto.TyplmChangeRequestDTO;
import com.hustcad.plm.pdm.ec.module.dto.TyplmIssueObjDTO;
import com.hustcad.plm.pdm.ec.module.vo.ChgRequestDetailVO;
import com.hustcad.plm.pdm.ec.service.TyplmChangeIssueService;
import com.hustcad.plm.pdm.ec.service.TyplmChangeRequestService;
import com.hustcad.plm.pdm.ec.service.TyplmEcAgainstDataService;
import com.hustcad.plm.pdm.ec.service.TyplmIssueAgainstDataService;
import com.hustcad.plm.pdm.flowbusiness.model.entity.FlowChangeIssueView;
import com.hustcad.plm.pdm.flowbusiness.model.entity.FlowChangeRequestView;
import com.hustcad.plm.pdm.flowbusiness.service.TyplmFlowChangeRequestViewService;
import com.hustcad.plm.pdm.form.model.vo.FormTemplateVO;
import com.hustcad.plm.pdm.form.service.TyplmFormTemplateService;
import com.hustcad.plm.pdm.type.service.TyplmTypeService;
import com.hustcad.plm.pdm.user.model.dto.PdmUserDTO;
import com.hustcad.plm.pdm.user.service.TyplmUserService;
import com.hustcad.plm.pdm.workflow.model.entity.FlowTaskRecord;
import com.hustcad.plm.pdm.workflow.model.entity.UserTaskDTO;
import com.hustcad.plm.pdm.workflow.model.entity.WorkFlow;
import com.hustcad.plm.pdm.workflow.model.entity.WorkFlowContainerView;
import com.hustcad.plm.pdm.workflow.service.TyplmWorkFlowContainerService;
import com.hustcad.plm.pdm.workflow.service.TyplmWorkFlowProcessService;
import com.hustcad.plm.pdm.workflow.service.TyplmWorkFlowService;
import com.hustcad.plm.workspace.dto.ObjNumberDTO;
import com.hustcad.plm.workspace.service.TyPlmWorkspaceObjectService;
import com.hustcad.plm.workspace.vo.ObjNumberErrorVO;
import com.ty.basic.constant.TableTypeConstrant;
import com.ty.basic.entity.CTyEntityBaseDO;
import com.ty.basic.entity.IdentifierEntity;
import com.ty.basic.entity.audit.AuditLogDO;
import com.ty.basic.entity.org.UserDO;
import com.ty.basic.session.TyAccountContext;
import com.ty.basic.utils.ArgumentUtils;
import cqrtplm.mapper.RTFormTemplateMapper;
import cqrtplm.service.RTChangeRequestService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
@Slf4j
public class RTChangeRequestServiceImpl implements RTChangeRequestService {
    @Resource
    private TyplmChangeIssueService typlmChangeIssueService;
    @Resource
    private TyplmTypeService typlmTypeService;
    @Resource
    private TyplmBasedRuleService typlmBasedRuleService;
    @Resource
    private TyplmSegmentCodeService typlmSegmentCodeService;
    @Resource
    TyplmWorkFlowService typlmWorkFlowService;
    @Resource
    private TyplmUserService typlmUserService;
    @Resource
    private TyplmLogger typlmLogger;
    @Resource
    private TyplmChangeRequestService typlmChangeRequestService;
    @Resource
    private TyPlmWorkspaceObjectService tyPlmWorkSpaceObjectService;
    @Resource
    private TyplmWorkFlowProcessService typlmWorkFlowProcessService;
    @Resource
    private TyplmEcAgainstDataService typlmEcAgainstDataService;
    @Resource
    private TyplmWorkFlowContainerService typlmWorkFlowContainerService;
    @Resource
    private TyplmIssueAgainstDataService typlmIssueAgainstDataService;
    @Resource
    private TyplmFlowChangeRequestViewService typlmFlowChangeRequestViewService;
    @Resource
    private TyplmFormTemplateService typlmFormTemplateService;
    @Resource
    private RTFormTemplateMapper formTemplateMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createECR(String workFlowContainerId) throws Exception {
        WorkFlowContainerView workFlowContainerView = typlmWorkFlowContainerService.getWorkFlowContainerDetailByPrimaryKey(
                new BigInteger(workFlowContainerId));
        if (!Objects.isNull(workFlowContainerView) && workFlowContainerView instanceof FlowChangeIssueView) {
            log.info("当前流程属于变更问题流程");
            FlowChangeIssueView flowChangeIssueView = (FlowChangeIssueView) workFlowContainerView;
            List<FlowTaskRecord> flowTaskRecordList = flowChangeIssueView.getFlowTaskRecordList();
            //获取问题报告对象
            TyplmChangeIssueDetailDTO changeIssueVO = flowChangeIssueView.getChangeIssueDTO();
            String issueName = changeIssueVO.getName();
            BigInteger containerOid = changeIssueVO.getContaineroid();
            String containerOtype = changeIssueVO.getContainerotype();
            IdentifierEntity issueEntity = new IdentifierEntity(changeIssueVO.getOid(), changeIssueVO.getOtype());
            List<String> partNumberList = new ArrayList<>();
            List<TyplmIssueObjDTO> typlmIssueObjList = this.typlmIssueAgainstDataService.listChangeIssueAffectedList(
                    issueEntity);
            for (TyplmIssueObjDTO typlmIssueObj : typlmIssueObjList) {
                partNumberList.add(typlmIssueObj.getObjectNumber());
            }
            List<String> userNameList = new ArrayList<>();
            userNameList.add(changeIssueVO.getCreatorName());
            //根据ECR的类型获取类型OID
            BigInteger typeOid = typlmTypeService.getTypeOidByName("CUSTOMER_ECR");
            //获取ECR类型关联的初始化规则
            TyplmBaseRuleBoundedObjDTO typeBasedRuleEditDTO = this.typlmBasedRuleService.getBaseRuleBoundedObjInfo(
                    typeOid,
                    containerOid,
                    containerOtype);
            //获取初始化规则中绑定的编码规则OID
            BigInteger ruleOid = typeBasedRuleEditDTO.getSegmentCodeOid();
            String ruleType = typeBasedRuleEditDTO.getSegmentCodeOtype();
            TyplmSegmentCodeConditionDTO param = new TyplmSegmentCodeConditionDTO();
            IdentifierEntity identifierEntity = new IdentifierEntity(ruleOid, ruleType);
            param.setRuleInfo(identifierEntity);
            param.setOtype("ty.inteplm.change.CTyChangeRequest");
            //根据编码规则创建ECR编码
            TyplmSegmentCodeRuleVO resultData = this.typlmSegmentCodeService.getSegmentFormData(param);
            String code = resultData.getCode();
            ObjNumberDTO objNumberDTO = new ObjNumberDTO();
            List list = new ArrayList();
            list.add(code);
            objNumberDTO.setObjNumberList(list);
            objNumberDTO.setObjOtype("ty.inteplm.change.CTyChangeRequest");
            //判断ECR编码是否已存在
            List<ObjNumberErrorVO> list1 = this.tyPlmWorkSpaceObjectService.judgeObjNumberIsExist(
                    objNumberDTO.getObjNumberList(), objNumberDTO.getObjOtype());
            if (list1 == null || list1.size() == 0) {

            }

            //组装创建ECR所需的基本信息
            TyplmChangeRequestDTO changeRequestDTO = new TyplmChangeRequestDTO();
            try {
                changeRequestDTO.setContaineroid(containerOid);
                changeRequestDTO.setContainerotype(containerOtype);
                changeRequestDTO.setTypeoid(typeOid);
                changeRequestDTO.setObjectNumber(code);
                changeRequestDTO.setName(issueName);
                changeRequestDTO.setFileList(null);
                changeRequestDTO.setIbaAttribute(changeIssueVO.getIbaAttribute());
                FormTemplateVO formTemplateVO = this.typlmFormTemplateService.getFormTemplateByType(typeOid);
                if (formTemplateVO != null) {
                    BigInteger oid = formTemplateVO.getOid();
                    String type = formTemplateVO.getOtype();
                    changeRequestDTO.setFormtemplateoid(oid);
                    changeRequestDTO.setFormtemplateotype(type);
                    changeRequestDTO.setFormData(formTemplateVO.getTemplatedata().toJSONString());
                }
                ChgRequestDetailVO changeRequest = this.typlmChangeRequestService.createChangeRequest(changeRequestDTO);
                //建立ECR与问题报告的关联
                IdentifierEntity mainObj = new IdentifierEntity(changeRequest.getOid(), changeRequest.getOtype());
                ArgumentUtils.checkArgumentNull(mainObj, "mainObj");
                List<IdentifierEntity> objectList = new ArrayList<>();
                IdentifierEntity entity = new IdentifierEntity(changeIssueVO.getOid(), changeIssueVO.getOtype());
                objectList.add(entity);
                ArgumentUtils.checkArgumentEmpty(objectList, "objectList");
                this.typlmChangeRequestService.createEcLinkObjByIdentifierEntity(mainObj, objectList);
                //将问题报告中受影响的对象添加到ECR中
                List<AffectedObjectDTO> affectobjectList = new ArrayList<>();
                for (TyplmIssueObjDTO typlmIssueObj : typlmIssueObjList) {
                    AffectedObjectDTO affectedObjectDTO = new AffectedObjectDTO(typlmIssueObj.getOid(),
                                                                                typlmIssueObj.getOtype(),
                                                                                typlmIssueObj.getDescription());
                    affectobjectList.add(affectedObjectDTO);
                }
                if (!affectobjectList.isEmpty()) {
                    List<BigInteger> oidList = this.typlmEcAgainstDataService.batchCreateAffectedLinkList(mainObj,
                                                                                                          affectobjectList);
                    oidList.forEach((item) -> this.typlmLogger.info(
                            new CTyEntityBaseDO(item, "ty.inteplm.change.CTyChangeAffectedLink"),
                            LogEventEnum.CRATE_OBJECT));

                }
                //封装Oid oType 到 IdentifierEntity
                IdentifierEntity identifier = getIdentifierEntity(changeRequest);
                //查询变更请求详细信息
                FlowChangeRequestView flowChgFormView = this.typlmFlowChangeRequestViewService.getEmptyFlowChgFormView(
                        identifier);
                //获取指定模板流程详细信息
                WorkFlow workFlow = getDefaultWorkFlow("ECR变更申请流程");//
                //获取 List<PdmUserDTO> userList
                List<PdmUserDTO> userList = getPdmUserDTOS(userNameList);
                //查询流程模板每个流程节点的详细信息，并设置节点参与者
                List<UserTaskDTO> userTaskList = getUserTaskDTOS(workFlow, userList, containerOid, containerOtype);
                //获取 FlowChangeRequestView
                FlowChangeRequestView flowChangeRequestView = getFlowChangeRequestView(userTaskList, workFlow,
                                                                                       flowChgFormView, userList);

                //启动流程
                this.typlmFlowChangeRequestViewService.insert(flowChangeRequestView);
                this.typlmWorkFlowProcessService.startProcess(flowChangeRequestView, true);
                //启动流程
                //                String key = "adapter:lock:workflow:" + workFlowContainerView.getCode();
                //                try {
                //                    this.redisLockService.lock(key);
                //                    this.typlmWorkFlowObjectPackageService.insert(containerView);
                //                    this.typlmWorkFlowProcessService.startProcess(containerView, true);
                //                } finally {
                //                    this.redisLockService.unlock(key);
                //                }
            } catch (Exception exception) {
                AuditLogDO auditLogDO = new AuditLogDO();
                auditLogDO.setObjoid(BigInteger.ZERO);
                auditLogDO.setObjotype(changeRequestDTO.getOtype());
                auditLogDO.setContaineroid(changeRequestDTO.getContaineroid());
                auditLogDO.setContainerotype(changeRequestDTO.getContainerotype());
                auditLogDO.setTargettype(changeRequestDTO.getTypeDefName());
                auditLogDO.setTargetname(changeRequestDTO.getName());
                auditLogDO.setTargetnumber(changeRequestDTO.getObjectNumber());
                auditLogDO.setTargetsecuritylabels(changeRequestDTO.getSecuritylabels());
                auditLogDO.setLifecyclestageotype(changeRequestDTO.getLifecyclestageotype());
                auditLogDO.setLifecyclestageoid(changeRequestDTO.getLifecyclestageoid());
                auditLogDO.setLifecyclestatekey(changeRequestDTO.getLifecyclestagekey());
                this.typlmLogger.errorInfo(LogEventEnum.CRATE_OBJECT, auditLogDO, exception);
                throw exception;
            }
        }
    }

    /**
     * 封装变更对象
     *
     * @param changeRequest
     * @return
     */
    private @NotNull IdentifierEntity getIdentifierEntity(ChgRequestDetailVO changeRequest) {
        IdentifierEntity identifierEntity = new IdentifierEntity();
        identifierEntity.setOid(changeRequest.getOid());
        identifierEntity.setOtype(changeRequest.getOtype());
        return identifierEntity;
    }

    private FlowChangeRequestView getFlowChangeRequestView(List<UserTaskDTO> userTaskList, WorkFlow workFlow,
                                                           FlowChangeRequestView flowChgFormView,
                                                           List<PdmUserDTO> userList) {
        FlowChangeRequestView flowChangeRequestView = new FlowChangeRequestView();
        ChgRequestDetailVO chgRequestDetailVO = flowChgFormView.getChgRequestDetailVO();
        flowChangeRequestView.setChgRequestDetailVO(chgRequestDetailVO);
        flowChangeRequestView.setOid(flowChgFormView.getOid());
        flowChangeRequestView.setCodeNumber("WT" + System.currentTimeMillis());
        flowChangeRequestView.setOtype(TableTypeConstrant.TY_WORKFLOWCONTAINER_OTYPE);
        flowChangeRequestView.setName(
                chgRequestDetailVO.getObjectNumber() + "," + chgRequestDetailVO.getName() + "_变更审批流程");

        flowChangeRequestView.setWorkFlowId(workFlow.getOid());
        flowChangeRequestView.setWorkFlowName(workFlow.getName());
        flowChangeRequestView.setDeploymentId(workFlow.getDeploymentId());

        flowChangeRequestView.setUserTaskList(userTaskList);
        flowChangeRequestView.setEmergencyDegree("commonly");
        flowChangeRequestView.setContainerOid(flowChgFormView.getContainerOid());
        flowChangeRequestView.setContainerOtype(flowChgFormView.getContainerOtype());
        flowChangeRequestView.setBaseObjectOtype(flowChgFormView.getBaseObjectOtype());
        flowChangeRequestView.setBaseObjectOid(flowChgFormView.getBaseObjectOid());

        UserDO user = TyAccountContext.getUser();
        flowChangeRequestView.setCreatorOid(user.getOid());
        flowChangeRequestView.setCreatorOtype(TableTypeConstrant.TY_USER_OTYPE);
        flowChangeRequestView.setUpdaterOid(user.getOid());
        flowChangeRequestView.setUpdaterOtype(TableTypeConstrant.TY_USER_OTYPE);

        flowChangeRequestView.setManagerList(userList);

        IdentifierEntity identifierEntity = new IdentifierEntity();
        identifierEntity.setOid(flowChgFormView.getOid());
        identifierEntity.setOtype(flowChgFormView.getOtype());
        flowChangeRequestView.setIdentifierRef(identifierEntity);
        return flowChangeRequestView;
    }

    /**
     * 获取流程中每个任务节点详细信息，并设置节点参与者
     *
     * @return
     */
    public @NotNull List<UserTaskDTO> getUserTaskDTOS(WorkFlow workFlow, List<PdmUserDTO> userList,
                                                      BigInteger containerOid, String containerOtype) {
        List<UserTaskDTO> userTaskList = typlmWorkFlowContainerService.getAllUserTask(workFlow.getOid(),
                                                                                      containerOid,
                                                                                      containerOtype);
        //遍历设置流程节点的参与者
        if (CollUtil.isNotEmpty(userList)) {
            UserTaskDTO userTaskDTO = userTaskList.get(0);
            userTaskDTO.setUserList(userList);
        }
        return userTaskList;
    }

    /**
     * 获取List<PdmUserDTO> 参与者信息
     *
     * @param userNameList
     * @return
     */
    public List<PdmUserDTO> getPdmUserDTOS(List<String> userNameList) {
        List<UserDO> userDOS = typlmUserService.queryUserByNameList(userNameList);
        List<PdmUserDTO> pdmUserDTOList = new ArrayList<>();
        if (CollUtil.isNotEmpty(userDOS)) {
            pdmUserDTOList = convertToPdmUserDTO(userDOS);
        }
        return pdmUserDTOList;
    }

    public WorkFlow getDefaultWorkFlow(String templateName) {
        Example example = new Example(WorkFlow.class, true, true);
        example.createCriteria().andEqualTo("name", templateName);
        List<WorkFlow> workFlowList = this.typlmWorkFlowService.simpleQueryListByExample(example);
        if (ObjectUtils.isEmpty(workFlowList)) {
            //            throw new Exception("");
        }
        return workFlowList.get(0);
    }

    public List<PdmUserDTO> convertToPdmUserDTO(List<UserDO> userDOList) {
        List<PdmUserDTO> userList = new ArrayList<>();
        if (CollUtil.isEmpty(userDOList)) {
            return userList;
        }
        for (UserDO userDO : userDOList) {
            PdmUserDTO pdmUserDTO = convertPdmUserDTO(userDO);
            userList.add(pdmUserDTO);
        }
        return userList;
    }

    private PdmUserDTO convertPdmUserDTO(UserDO userDO) {
        TyplmLoggerUtil.debug(log, () -> {
            return "convertPdmUserDTO 方法入参userDO ==> 【{}】";
        }, () -> {
            return new Object[]{JSONObject.toJSONString(userDO)};
        });
        PdmUserDTO pdmUserDTO = new PdmUserDTO();
        BeanUtils.copyProperties(userDO, pdmUserDTO);
        pdmUserDTO.setOid(userDO.getOid().toString());
        pdmUserDTO.setOtype(userDO.getOtype());
        pdmUserDTO.setAccount(userDO.getName());
        pdmUserDTO.setUsername(userDO.getFullname());
        TyplmLoggerUtil.debug(log, () -> {
            return "convertPdmUserDTO 返回值pdmUserDTO ==> 【{}】";
        }, () -> {
            return new Object[]{JSONObject.toJSONString(pdmUserDTO)};
        });
        return pdmUserDTO;
    }

}
